/*
 * expr.y : A simple yacc expression parser
 *          Based on the Bison manual example. 
 */

%{
   #include <fcntl.h>
   #include <stdarg.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <sys/types.h>
   #include <unistd.h>
   
   typedef struct TabOfSymbol * TabOfSymbol;
   struct TabOfSymbol {
      char* ident;
      char* class; // function, glob, loc, arg
      char* type;  // int, char
      int address;
   };
   
   typedef struct AllTabOfSymbol * AllTabOfSymbol;
   struct AllTabOfSymbol {
      int nb_line;
      int tab_size;
      TabOfSymbol *tab;
   };
   
   TabOfSymbol create_TabOfSymbol(char* id, char* cl, char* ty, int ad) {
      TabOfSymbol line = malloc(sizeof(struct TabOfSymbol));
      line->ident = id;
      line->class = cl;
      line->type = ty;
      line->address = ad;
      return line;
   }
   
   AllTabOfSymbol create_AllTabOfSymbol(void) {
      AllTabOfSymbol ATOS = malloc(sizeof(struct AllTabOfSymbol));
      ATOS->nb_line = 0;
      ATOS->tab_size = 10;
      ATOS->tab = malloc(10 * sizeof(struct TabOfSymbol));;
      return ATOS;
   }
   
   AllTabOfSymbol add_line(AllTabOfSymbol ATOS, TabOfSymbol line) {
      if( ATOS->nb_line < ATOS->tab_size ) {
	     ATOS->tab[ATOS->nb_line] = line; // indice du tableau commence a 0 donc ATOS->nb_line
	     ATOS->nb_line++;
	  }
	  else if( ATOS->nb_line == ATOS->tab_size ) {
	     ATOS->tab_size *= 2;
		 TabOfSymbol tmp[ATOS->tab_size];
		 int i;
		 for( i=0; i<(ATOS->tab_size)/2; i++) {
		    tmp[i] = ATOS->tab[i];
		 }
         ATOS->tab = tmp;
         free(tmp);
	     ATOS->tab[ATOS->nb_line] = line; // indice du tableau commence a 0 donc ATOS->nb_line
	     ATOS->nb_line++;
	  }
      return ATOS;
   }
   
   void dump_ATOS(AllTabOfSymbol ATOS) {
      printf("\n -   type - classe -  ident - address - \n");
      printf(" --------------------------------------\n");
      int i;
      for(i=0; i<ATOS->nb_line; i++) {
         printf(" - %6s - %6s - %6s - %7d - \n", ATOS->tab[i]->ident,
                                                 ATOS->tab[i]->class,
                                                 ATOS->tab[i]->type,
                                                 ATOS->tab[i]->address);
      }
      printf(" --------------------------------------\n\n");
   }
   
   // Declaration des variables globales
   AllTabOfSymbol ATabOS;
   TabOfSymbol TabOS;
   
%}

%union {
	char * val;
}

%token equal not_equal sup_equal inf_equal logic_and logic_or
%token token_void token_int token_static token_return token_exit token_if token_else token_while
%token identificateur read_int nb_entier

%type <val> token_void token_int identificateur nb_entier DECL LISTPARAM '(' ')'

%%

PGM: 			   DECL FOLLOW  { printf("%s\n", $1); }
;

DECL:          token_int identificateur                                 { /* int a; */
                                                                 TabOS = create_TabOfSymbol("int", "glob", strdup($2), 12);
                                                                 add_line(ATabOS, TabOS);
                                                                 //printf("%s\n", strdup($2));
                                                                        }
             | token_static token_int identificateur                    {}
             | token_int identificateur '[' nb_entier ']'               {}
             | token_static token_int identificateur '[' nb_entier ']'  {}
             | token_int identificateur '(' SEQUELTYPE ')'              { /* Prototype */ }
             | token_void identificateur '(' SEQUELTYPE ')'             { /* Prototype */ }

             | token_int identificateur '(' LISTPARAM ')'               { /* Function */ }
             | token_void identificateur '(' LISTPARAM ')'              { /* Function */ }
;
LISTPARAM:                                         { /* modif */ }
             | PARAM                               {}
             | PARAM ',' LISTPARAM                 {}
;
PARAM:         token_int identificateur                    {}
             | token_int identificateur '[' nb_entier ']'  {}
;
FOLLOW:        ';' PGM                  {}
             | '{' BODYFUNC             {}
;
BODYFUNC:      DECL2 ';' BODYFUNC       {}
				 | INSTRUCT ';' BODYFUNC    {}
				 | ENDFUNC                  {}
;
DECL2:         token_int identificateur                                 {}
             | token_static token_int identificateur                    {}
             | token_int identificateur '[' nb_entier ']'               {}
             | token_static token_int identificateur '[' nb_entier ']'  {}
             | token_int identificateur '(' SEQUELTYPE ')'              { /* Prototype */ }
             | token_int identificateur '('  ')'                        { /* Call Function */ }
             | token_void identificateur '(' SEQUELTYPE ')'             { /* Prototype */ }
             | token_void identificateur '('  ')'                       { /* Call Function */ }
;
ENDFUNC:       '}'                      {}
				 | '}' PGM                  {}
;
SEQUELTYPE:    token_void               { /* Prototype or Function */ }
             | LISTTYPE                 { /* Function */ }
;
LISTTYPE:      nb_entier                { /* Function */ }
             | nb_entier ',' LISTTYPE   { /* Function */ }
;

INSTRUCT:      identificateur '=' EXP                        {}
             | identificateur '[' EXP ']' '=' EXP            {}
             | token_exit '(' nb_entier ')'                  {}
             | token_return EXP                              {}
             | token_return                                  {}
             | read_int '(' identificateur ')'               { /*
			    | token_if '(' EXP ')' INSTRUCT else INSTRUCT
																					*/	}
				 | token_if '(' EXP ')' INSTRUCT                 {}
             | token_while '(' EXP ')' INSTRUCT              {}
             | token_while '(' EXP ')' '{' LISTINSTRUCT '}'  {}
             | EXP                                           {}
;
LISTINSTRUCT:                                                {}
             | INSTRUCT ';' LISTINSTRUCT                     {}
;
EXP:           EXP OPBIN EXP          					{}
				 | '-' EXP                             {}
             | '!' EXP                             {}
             | '(' EXP ')'                         {}
             | identificateur                      {}
             | nb_entier                           {}
             | identificateur '(' SEQUELARG ')'    {}
             | identificateur '[' EXP ']'          {}
;
SEQUELARG:                      {}
             | LISTARG          {}
;
LISTARG:       EXP              {}
             | EXP ',' LISTARG  {}
;
OPBIN:         '>'              {  }
             | '<'              {  }
             | equal            { /* == */ }
             | inf_equal        { /* <= */ }
             | sup_equal        { /* >= */ }
             | not_equal        { /* != */ }
             | '+'              {  }
             | '-'              {  }
             | '*'              {  }
             | '/'              {  }
             | '%'              {  }
             | logic_or         { /* || */ }
             | logic_and        { /* && */ }
;

%%

yyerror(char *message) {
   printf("%s\n", message);
}


char* concatener(char* text, ... ) {
	va_list varg;         // déclaration de la liste des parametres
	va_start(varg, text); // initialisation du premier parametre
	char* buffer = text;  // buffer qui contiendra toutes les chaines concatenees
	char* current_text = NULL; // buffer qui contient le parametre courant

   current_text = va_arg(varg, char*);
	while(current_text != NULL ) {
		asprintf(&buffer, "%s%s", buffer, current_text);
      current_text = va_arg(varg, char*);
	}
	va_end(varg);
	//printf("%s\n", buffer);
	return buffer;
}



int main(int argc, char *argv[])
{

   FILE * MyFile;
   MyFile = fopen("output.s" , "w+");

   char* buffer = concatener(//"	.file	\"test.c\"\n",
                             "	.text\n",
                             "	.globl	main\n",
                             "	.type	main, @function\n",
                             "main:\n",
                             ".LFB0:\n",
                             "	.cfi_startproc\n",
                             "	pushq	%rbp\n",
                             "	.cfi_def_cfa_offset 16\n",
                             "	.cfi_offset 6, -16\n",
                             "	movq	%rsp, %rbp\n",
                             "	.cfi_def_cfa_register 6\n",
                             NULL);
   fprintf (MyFile, "%s", buffer);

   ATabOS = create_AllTabOfSymbol();
   
   yyparse();
   
   dump_ATOS(ATabOS);
   
   buffer = concatener("	popq	%rbp\n",
                       "	.cfi_def_cfa 7, 8\n",
                       "	ret\n",
                       "	.cfi_endproc\n",
                       ".LFE0:\n",
                       "	.size	main, .-main\n",
                       "	.ident	\"GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1\"\n",
                       "	.section	.note.GNU-stack,\"\",@progbits\n",
                       NULL);
   fprintf (MyFile, "%s", buffer);
   fclose(MyFile);
   return(0);
}









